package com.manolovn.trianglify;

import com.manolovn.trianglify.domain.Point;
import com.manolovn.trianglify.domain.Triangle;
import com.manolovn.trianglify.generator.color.ColorGenerator;
import com.manolovn.trianglify.generator.point.PointGenerator;
import com.manolovn.trianglify.renderer.TriangleRenderer;
import com.manolovn.trianglify.triangulator.DelaunayTriangulator;
import com.manolovn.trianglify.triangulator.Triangulator;

import ohos.agp.components.element.ShapeElement;
import ohos.agp.render.Canvas;

import ohos.media.image.common.PixelFormat;

import java.util.Vector;

/**
 * Trianglify drawable
 */
public class TrianglifyDrawable extends ShapeElement {
    private PointGenerator pointGenerator;
    private Triangulator triangulator;
    private TriangleRenderer triangleRenderer;

    private int width;
    private int height;
    private int bleedX;
    private int bleedY;
    private int cellSize;
    private int variance;

    private Vector<Point> points;
    private Vector<Triangle> triangles;

    private final Object lock = new Object();

    // Used with triangulateInBackground
    Boolean ready = false;

    public TrianglifyDrawable(
            int bleedX,
            int bleedY,
            int cellSize,
            int variance,
            ColorGenerator colorGenerator,
            PointGenerator pointGenerator) {
        super();

        this.bleedX = bleedX;
        this.bleedY = bleedY;
        this.cellSize = cellSize;
        this.variance = variance;
        this.pointGenerator = pointGenerator;

        triangulator = new DelaunayTriangulator();
        triangleRenderer = new TriangleRenderer(colorGenerator);
    }

    /**
     * this method is used to set component width and height and start async task
     *
     * @param width refers to width of the component
     * @param height refers to height of the component
     */
    protected void onBoundsChange(int width, int height) {
        this.width = width;
        this.height = height;
        triangulateInBackground();
    }

    /**
     * this method is used to render triangles in canvas
     *
     * @param canvas refers to paint triangles on screen
     */
    public void draw(Canvas canvas) {
        triangulateInBackground();
        if (ready && triangles != null) {
            triangleRenderer.render(triangles, canvas);
        }
    }

    /**
     * this method is used to set alpha or transparency
     *
     * @param alpha transparency parameter
     */
    @Override
    public void setAlpha(int alpha) {
    }

    /**
     * this method is used to get pixel format opacity
     *
     * @return int PixelFormat opacity value
     */
    public int getOpacity() {
        return PixelFormat.ARGB_8888.getValue();
    }

    /**
     * to initialize all UI Components
     */
    public void setVariance(int variance) {
        if(variance <= 0) {
            return;
        }
        this.variance = variance;
        triangulateInBackground();
    }

    /**
     * this method is used to set cell size in trianglify
     *
     * @param cellSize refers to size of cell that need to be set
     */
    public void setCellSize(int cellSize) {
        if(cellSize <= 0) {
            return;
        }
        this.cellSize = cellSize;
        triangulateInBackground();
    }

    /**
     * this method is used to generate and set color in trianglify
     *
     * @param colorGenerator object that need to be pass to set on screen
     */
    public void setColorGenerator(ColorGenerator colorGenerator) {
        triangleRenderer = new TriangleRenderer(colorGenerator);
        triangulateInBackground();
    }

    /**
     * this method is used to set point in trianglify
     *
     * @param pointGenerator need to be pass to render point
     */
    public void setPointGenerator(PointGenerator pointGenerator) {
        this.pointGenerator = pointGenerator;
        triangulateInBackground();
    }

    private void triangulateInBackground() {
        TriangulateAsyncTask task = new TriangulateAsyncTask();
        task.execute();
    }

    private class TriangulateAsyncTask extends AsyncTask<Void, Void, Void> {
        /**
         * this method is used to run long running task in background
         *
         * @param params parameters need to be pass
         */
        @Override
        protected Void doInBackground(Void... params) {
            synchronized (lock) {
                ready = false;
                pointGenerator.setBleedX(bleedX);

                pointGenerator.setBleedY(bleedY);

                points = pointGenerator.generatePoints(width, height, cellSize, variance);

                if (points.size() >= 3) {
                    triangles = triangulator.triangulate(points);
                }

                ready = true;
            }
            return null;
        }

        /**
         * this method will be call on main thread to show result from doInBackground
         *
         * @param aVoid void parameter
         */
        @Override
        protected void onPostExecute(Void aVoid) {
        }
    }
}
